<?php

namespace App\Http\Controllers\Admin;

use App\Http\Controllers\Controller;
use App\Models\AdminOperationLog;
use App\Models\Invoice;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Storage;

class InvoiceController extends Controller
{
    public function index(Request $request): JsonResponse
    {
        $query = Invoice::with([
            'tenant:id,name,company_name',
            'landingCompany:id,name,short_name',
        ]);

        if ($request->filled('status')) {
            $statuses = (array) $request->input('status');
            $query->whereIn('status', $statuses);
        }

        if ($request->filled('tenant_keyword')) {
            $keyword = trim($request->input('tenant_keyword'));
            $query->whereHas('tenant', function ($q) use ($keyword) {
                $q->where('name', 'like', "%{$keyword}%")
                    ->orWhere('company_name', 'like', "%{$keyword}%");
            });
        }

        if ($request->filled('landing_company_id')) {
            $query->where('landing_company_id', $request->input('landing_company_id'));
        }

        $sortBy = $request->input('sort_by', 'application_time');
        $sortOrder = $request->input('sort_order', 'desc');

        if (! in_array($sortBy, ['application_time', 'invoice_amount', 'status', 'created_at'])) {
            $sortBy = 'application_time';
        }

        $query->orderBy($sortBy, $sortOrder === 'asc' ? 'asc' : 'desc');

        $perPage = max(1, min((int) $request->input('per_page', 15), 100));

        $paginator = $query->paginate($perPage);

        return response()->json([
            'code' => 0,
            'message' => '获取发票申请列表成功',
            'data' => [
                'items' => $paginator->items(),
                'pagination' => [
                    'total' => $paginator->total(),
                    'per_page' => $paginator->perPage(),
                    'current_page' => $paginator->currentPage(),
                    'last_page' => $paginator->lastPage(),
                ],
            ],
        ]);
    }

    public function statusOptions(): JsonResponse
    {
        $options = collect(Invoice::getStatusOptions())
            ->map(function ($label, $value) {
                return [
                    'value' => $value,
                    'label' => $label,
                ];
            })->values()->toArray();

        return response()->json([
            'code' => 0,
            'message' => '获取状态选项成功',
            'data' => $options,
        ]);
    }

    public function accept(Request $request, Invoice $invoice): JsonResponse
    {
        if ($invoice->status !== Invoice::STATUS_NEW) {
            return response()->json([
                'code' => 400,
                'message' => '仅限新建状态的申请可以受理',
                'data' => null,
            ], 400);
        }

        $admin = $request->user('admin');

        $invoice->update([
            'status' => Invoice::STATUS_BILLING,
            'processed_at' => now(),
            'processed_by' => $admin?->id,
        ]);

        AdminOperationLog::log(
            $admin?->id,
            'invoice.accept',
            'invoice',
            Invoice::class,
            $invoice->id,
            '受理开票申请'
        );

        return response()->json([
            'code' => 0,
            'message' => '开票申请已受理',
            'data' => $invoice->fresh(['tenant', 'landingCompany']),
        ]);
    }

    public function reject(Request $request, Invoice $invoice): JsonResponse
    {
        if (! in_array($invoice->status, [Invoice::STATUS_NEW, Invoice::STATUS_BILLING], true)) {
            return response()->json([
                'code' => 400,
                'message' => '仅限新建或开票中的申请可以拒绝',
                'data' => null,
            ], 400);
        }

        $validated = $request->validate([
            'reason' => 'required|string|max:500',
        ]);

        $admin = $request->user('admin');

        $invoice->update([
            'status' => Invoice::STATUS_REJECTED,
            'rejection_reason' => $validated['reason'],
            'processed_at' => now(),
            'processed_by' => $admin?->id,
        ]);

        AdminOperationLog::log(
            $admin?->id,
            'invoice.reject',
            'invoice',
            Invoice::class,
            $invoice->id,
            '拒绝开票申请',
            ['reason' => $validated['reason']]
        );

        return response()->json([
            'code' => 0,
            'message' => '开票申请已拒绝',
            'data' => $invoice->fresh(['tenant', 'landingCompany']),
        ]);
    }

    public function upload(Request $request, Invoice $invoice): JsonResponse
    {
        if ($invoice->status !== Invoice::STATUS_BILLING) {
            return response()->json([
                'code' => 400,
                'message' => '仅限开票中的申请可以上传发票',
                'data' => null,
            ], 400);
        }

        $validated = $request->validate([
            'invoice_file' => 'required|file|mimes:pdf,jpg,jpeg,png|max:10240',
            'express_tracking_number' => 'nullable|string|max:100',
        ]);

        $admin = $request->user('admin');

        $disk = config('invoice.storage_disk', config('filesystems.default', 'local'));
        $availableDisks = array_keys(config('filesystems.disks', []));
        if (! in_array($disk, $availableDisks, true)) {
            $disk = config('filesystems.default', 'local');
        }

        $storage = Storage::disk($disk);

        $file = $validated['invoice_file'];
        $path = sprintf('invoices/%s', $invoice->id);
        $filename = sprintf('%s.%s', now()->format('Ymd_His'), $file->getClientOriginalExtension() ?: 'pdf');

        $storedPath = $storage->putFileAs($path, $file, $filename, ['visibility' => 'private']);

        if (! $storedPath) {
            return response()->json([
                'code' => 500,
                'message' => '发票文件上传失败，请稍后重试',
                'data' => null,
            ], 500);
        }

        DB::transaction(function () use ($invoice, $validated, $admin, $storedPath) {
            $invoice->update([
                'invoice_file_path' => $storedPath,
                'express_tracking_number' => $validated['express_tracking_number'] ?? $invoice->express_tracking_number,
                'status' => Invoice::STATUS_BILLED,
                'issued_at' => now(),
                'processed_at' => now(),
                'processed_by' => $admin?->id,
            ]);
        });

        AdminOperationLog::log(
            $admin?->id,
            'invoice.upload',
            'invoice',
            Invoice::class,
            $invoice->id,
            '上传发票并标记已开票',
            ['invoice_file_path' => $storedPath]
        );

        return response()->json([
            'code' => 0,
            'message' => '发票已上传并标记为已开票',
            'data' => $invoice->fresh(['tenant', 'landingCompany']),
        ]);
    }

    public function void(Request $request, Invoice $invoice): JsonResponse
    {
        if ($invoice->status !== Invoice::STATUS_BILLED) {
            return response()->json([
                'code' => 400,
                'message' => '仅限已开票的申请可以作废',
                'data' => null,
            ], 400);
        }

        $admin = $request->user('admin');

        $invoice->update([
            'status' => Invoice::STATUS_VOIDED,
            'processed_at' => now(),
            'processed_by' => $admin?->id,
        ]);

        AdminOperationLog::log(
            $admin?->id,
            'invoice.void',
            'invoice',
            Invoice::class,
            $invoice->id,
            '作废已开票申请'
        );

        return response()->json([
            'code' => 0,
            'message' => '发票已作废',
            'data' => $invoice->fresh(['tenant', 'landingCompany']),
        ]);
    }

    public function preview(Invoice $invoice)
    {
        if (! $invoice->invoice_file_path) {
            abort(404, '发票文件不存在');
        }

        $disk = config('invoice.storage_disk', config('filesystems.default', 'local'));
        $storage = Storage::disk($disk);

        if (! $storage->exists($invoice->invoice_file_path)) {
            abort(404, '发票文件不存在');
        }

        $filename = basename($invoice->invoice_file_path) ?: ($invoice->invoice_number . '.pdf');

        return $storage->response($invoice->invoice_file_path, $filename, [
            'Content-Disposition' => 'inline; filename="' . $filename . '"',
        ]);
    }
}
